因為今天比較忙,剩沒多少時間,補上之前欠的內容
我們在 [Day4] .Net Core 中的相依性注入 - 1 跟[Day5] .Net Core 中的相依性注入 - 2 中有提到一些比較重要的觀念與物件
IServiceCollection
IServiceProvider
IServiceScope
IServiceProviderFactory
ServiceDescriptor
今天來介紹最核心的物件 ServiceProviderEngine
跟 ServiceProviderEngineScope
ServiceProviderEngine
是最後的提供出執行個體的那個人物件,在一個dotnet core的應用程式範圍中他只存在全域唯一的一個,ServiceProviderEngineScope
則是負責管理範圍內生命週期的物件
IServiceProviderEngineScope
,節錄幾個方法與屬性
internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable, IServiceScopeFactory{
internal IList<object> Disposables{ get; }
internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; }
internal ServiceProvider RootProvider { get; }
public IServiceProvider ServiceProvider => this;
public IServiceScope CreateScope() => RootProvider.CreateScope();
public object GetService(Type serviceType)
{
if (_disposed)
{
ThrowHelper.ThrowObjectDisposedException();
}
return RootProvider.GetService(serviceType, this);
}
}
我們之前有提過 IServiceProvider
會有一個ResolvedServices
紀錄已建立的物件,
一個 Disposables
存放要Dispose的物件
ServiceProviderEngine
既是 IServiceScope
也是 IServiceScopeFactory
所以該有的他都有
有趣的是他的 ServiceProvider 是指向自己的 所以當對她使用GetService<IServiceProvider>
時最後拿到的就是他自己。
本身是一個抽象類別,定義了類別如何被實現
internal abstract class ServiceProviderEngine
{
public abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);
}
主要有4種實作方式
ILEmitServiceProviderEngine
: 透過IL Emit的方式提供執行個體RuntimeServiceProviderEngine
: 透過反射取得執行個體ExpressionsServiceProviderEngine
: 利用Expression Tree來產生執行個體DynamicServiceProviderEngine
(CompiledServiceProviderEngine
背後的實作): Dotnet core 預設
使用的方式,主要是透過當前的執行序池的請求數量決定要走上面3種的的哪一種,走ILEmitServiceProviderEngine
或 RuntimeServiceProviderEngine
取決於runtime支不支援Reflection Emit
更細節的物件實際被產生就下細看這三個類別了(超難懂我放棄)
這邊只大概提 Runtime的產生實作的作法 (我跟expression 是不熟悉的陌生人,就是不認識XD,懂IL我就不會在這裡了)
主要有幾個步驟,不貼程式了
ServiceDescriptor
轉成ServiceCallSite
物件,我們在前面有提到ServiceDescriptor
ImplementXXX
的屬性,會分別對應到不同的ServiceCallSite
,以ServiceDescriptor.ImplementationType
為例,當我們使用的這個方式註冊Service時Services.AddScope<ISampleService,SampleService>
,會建立一個ServiceDescriptor.ImplementationType
= Typeof(SampleService)
的ServiceDescriptor
ConstructorCallSite
的物件,裡面紀錄了一個這個ImplementType
參數最多的建構式的資訊ConstructorInfo.Invoke Sample
var constructorInfos = typeof(SampleService).GetConstructors().OrderByDescending(x=>x.GetParameters().Length).ToList();
var withConstructorInstance = (ISampleService) constructorInfos[0].Invoke(new object?[]{"Eric"});
var withoutConstructorInstance = (ISampleService) constructorInfos[1].Invoke(null);
withConstructorInstance.SayHello();
withoutConstructorInstance.SayHello();
public interface ISampleService
{
void SayHello();
}
public class SampleService : ISampleService
{
private readonly string _a;
public SampleService()
{
}
public SampleService(string a)
{
_a = a;
}
public void SayHello()
{
if (_a is not null)
{
Console.WriteLine($"Hello World!, {_a}");
}
else
{
Console.WriteLine("Hello World!");
}
}
}
其實裡面還包含了快取,遞迴依賴等處理,太複雜了pass